#include <windows.h>
#include <stdio.h>

#define GDT_SIZE 65536 + sizeof(TABLE_INFO)
#define DOUBLE_GDT_SIZE 2 * GDT_SIZE
#define GDT_ENTRY_SIZE 8
     
#pragma pack(push, 1)	 
struct TABLE_INFO
{
	WORD  size;
	DWORD base;
};
#pragma pack(pop)

#pragma pack(push, 1)
struct Descriptor
{
     WORD limit_l;
     WORD base_l;
     BYTE base_m;
     BYTE access;
     BYTE limit_h:4;
	 BYTE flags:4;
     BYTE base_h;
};
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct LDT_HEADER
{
	UINT16 rpl:2;
	UINT16 ti:1;
	UINT16 index:13;
};
#pragma pack(pop)



void PrintTable(char* buffer)
{
	Descriptor* descriptor;
	TABLE_INFO* info = (TABLE_INFO*) buffer;
	
	printf("GDT addr: %u\nGDT size: %u\n", info->base, info->size);
	
	descriptor = (Descriptor*) (buffer + sizeof(TABLE_INFO));
	
	for (int i = 0; i < info->size / GDT_ENTRY_SIZE; ++i) {
	
		printf("Limit 0:15 %d, Base 16:31 %d, Base 32:39 %d, Access 40:47 %d, Limit 48:51 %d, Flags 52:55 %d, Base 56:63 %d\n",
			descriptor->limit_l, 
			descriptor->base_l, 
			descriptor->base_m, 
			descriptor->access, 
			descriptor->limit_h, 
			descriptor->flags, 
			descriptor->base_h);
		
		descriptor += 1;
	}
}

int main() {
	int status;
	
	HANDLE hDevice = CreateFile(	TEXT("\\\\.\\GDTD"),
								GENERIC_READ | GENERIC_WRITE,
								FILE_SHARE_READ|FILE_SHARE_WRITE,
								NULL,
								OPEN_EXISTING,
								FILE_ATTRIBUTE_NORMAL,
								NULL);

					
	if (hDevice == INVALID_HANDLE_VALUE) {
		printf("Failed to obtain file handle to device: %s with Win32 error code: %d\n", GetLastError() );
		return 1;
	}

	printf("Succeeded in obtaining handle to device.\n");

	printf("Attempting to read from device...\n");
	char buffer[GDT_SIZE];
	DWORD bytes_read;
	status = ReadFile(hDevice, buffer, GDT_SIZE, &bytes_read, NULL);
	
	printf("butes read: %d\n", bytes_read);
	
	if (!status) {
		printf("Failed on call to ReadFile - error: %d\n", GetLastError());
		return 1;
	}
	 PrintTable(buffer);
	
	TABLE_INFO* gdt_info = (TABLE_INFO*)buffer;
	Descriptor* gdt_first = (Descriptor*)(buffer + sizeof(TABLE_INFO));

	
	LDT_HEADER ldt_header;
	
	short i = 12345;
	__asm {
		// SLDT ldt_header
		sldt i;
	};
	
	printf("%d\n", i); // I have no idea why sldt ALWAYS returns zero. Can do nothing with this.
	
	

	// printf("LDT header: rpl: %d, ti: %d index: %d\n", ldt_header.rpl, ldt_header.ti, ldt_header.index);
	
	// Descriptor* desc = gdt_first + ldt_header.index;
	
	// printf("GDT: base: %u\n", gdt_info->base);
	// printf("LDT: base: %u limit %u\n", GetBase(*desc), GetLimit(*desc));
	
	
	
	
	printf("Attempting to close device...\n");
	
	status = CloseHandle(hDevice);
	if (!status) {
		printf("Failed on call to CloseHandle - error: %d\n", GetLastError() );
		return 1;
	}
	printf("Succeeded in closing device...exiting normally\n");
	return 0;
}


// DWORD GetLimit(Descriptor desc)
// {
	// return desc.limit_l + (desc.limit_h << 16);
// }

//DWORD GetBase(Descriptor desc) 
//{
//	return desc.base_l + (desc.base_m << 16) + (desc.base_h << 24);
        // DWORD base = 0;
        
        // base = base + desc.base_l;
        // base = base << 8;
        // base = base + desc.base_23_16;
        // base = base << 16;
        // base = base + desc.base_15_00;

        // return base;
//}


	